/**
 * @file pcap_read.h
 * @brief
 * @author thewangcj (thewangcj@gmail.com)
 * @version 0.1
 * @date 2021-07-12 22:07:64
 */
#ifndef __PCAP_INFO__
#define __PCAP_INFO__
#include <arpa/inet.h>
#include <pcap.h>

typedef unsigned char u_char;
typedef unsigned short int u_short;
typedef unsigned int u_int;

#define ETHER_ADDR_LEN 6
#define UDP_HEADER_LEN 8
#define KERBEROS_VER 0x05
#define KERBEROS_AS_REQ 0x0a
#define KERBEROS_AS_REP 0x0b
#define KERBEROS_TGS_REQ 0x0c
#define KERBEROS_TGS_REP 0x0d
#define KERBEROS_AP_REQ 0x0e
#define KERBEROS_AP_REP 0x0f
#define KERBEROS_ERROR 0x1e

#define MAX_NAME_LEN 48

/**
 * Ethernet header
 */
struct packet_ethernet {
    u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */
    u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */
    u_short ether_type;                 /* IP? ARP? RARP? etc */
};

enum PRO_TPYE {
    IPV4 = 0x8,
    IPV6 = 0xdd86,
    ARP  = 0x608,
    TCP  = 0x6,
    UDP  = 0x11,
};

/**
 *  IP 头部
 */
struct packet_ip {
    u_char ip_vhl;                 /* version << 4 | header length >> 2 */
    u_char ip_tos;                 /* type of service */
    u_short ip_len;                /* total length */
    u_short ip_id;                 /* identification */
    u_short ip_off;                /* fragment offset field */
#define IP_RF 0x8000               /* reserved fragment flag */
#define IP_DF 0x4000               /* don't fragment flag */
#define IP_MF 0x2000               /* more fragments flag */
#define IP_OFFMASK 0x1fff          /* mask for fragmenting bits */
    u_char ip_ttl;                 /* time to live */
    u_char ip_p;                   /* protocol */
    u_short ip_sum;                /* checksum */
    struct in_addr ip_src, ip_dst; /* source and dest address */
};
#define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)
#define IP_V(ip) (((ip)->ip_vhl) >> 4)

/**
 * TCP header
 */
typedef u_int tcp_seq;
struct packet_tcp {
    u_short th_sport; /* source port */
    u_short th_dport; /* destination port */
    tcp_seq th_seq;   /* sequence number */
    tcp_seq th_ack;   /* acknowledgement number */
    u_char th_offx2;  /* data offset, rsvd */
#define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4)
    u_char th_flags;
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
#define TH_ECE 0x40
#define TH_CWR 0x80
#define TH_FLAGS (TH_FIN | TH_SYN | TH_RST | TH_ACK | TH_URG | TH_ECE | TH_CWR)
    u_short th_win; /* window */
    u_short th_sum; /* checksum */
    u_short th_urp; /* urgent pointer */
};

struct packet_udp {
    u_short uh_sport; /* 源端口 */
    u_short uh_dport; /* 目的端口 */
    u_short uh_len;   /* udp 头部长度 */
    u_short uh_sum;   /* 校验和 */
};

struct packet_arp {
    u_char ah_universal[8];
    u_char ah_smac[6];
    struct in_addr ip_src;
    u_char ah_dmac[6];
    struct in_addr ip_des;
};

/**
 * IPV6 header
 */
struct packet_ipv6 {
    u_int32_t ip_vhl;               /*头部32位，包括版本、DS字段、ECN、流标签*/
    u_short load_length;            /* 负载长度 */
    u_char next_header;             /* 下一个头部 */
    u_char limit;                   /* 跳数限制 */
    struct in6_addr ip_src, ip_dst; /* 源地址和目的地址 */
};

#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
#define SIZE_ETHERNET 14

typedef struct __ipv4_addr {
    union {
        uint32_t addr32;
        uint8_t addr8[4];
    };
} ipv4_addr_t;

typedef struct __ipv6_addr {
    union {
        uint64_t addr64[2];
        uint32_t addr32[4];
        uint16_t addr16[8];
        uint8_t addr8[16];
    };
} ipv6_addr_t;

/**
 * 五元组
 */
typedef struct ipv4_5tuple {
    ipv4_addr_t ip1;
    ipv4_addr_t ip2;
    uint16_t port1;
    uint16_t port2;
    uint32_t protocol;
} ipv4_5tuple;

typedef struct ipv6_5tuple {
    ipv6_addr_t ip1;
    ipv6_addr_t ip2;
    uint16_t port1;
    uint16_t port2;
    uint32_t protocol;
} ipv6_5tuple;

struct pctx {
    const u_char *packet;
    u_char *payload;
    u_int len;
    u_int ip_head_len;
    u_short ip_len;
    u_int payload_len;
};

typedef struct pctx *PPCTX;

void process_ip(PPCTX pctx);
void process_tcp(PPCTX pctx);
void process_udp(PPCTX pctx);
void loop_callback(u_char *, const struct pcap_pkthdr *, const u_char *);
#endif